home *** CD-ROM | disk | FTP | other *** search
/ Young Minds / Young Minds Interactive CD-ROM.ISO / rogue / monster.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-05-13  |  17.5 KB  |  829 lines

  1. /*
  2.  * monster.c
  3.  *
  4.  * This source herein may be modified and/or distributed by anybody who
  5.  * so desires, with the following restrictions:
  6.  *    1.)  No portion of this notice shall be removed.
  7.  *    2.)  Credit shall not be taken for the creation of this source.
  8.  *    3.)  This code is not to be traded, sold, or used for personal
  9.  *         gain or profit.
  10.  *
  11.  */
  12.  
  13. #ifndef CURSES
  14. #include <curses.h>
  15. #endif CURSES
  16. #include "rogue.h"
  17.  
  18. object level_monsters;
  19. boolean mon_disappeared;
  20.  
  21. char *m_names[] = {
  22.     "aquatar",
  23.     "bat",
  24.     "centaur",
  25.     "dragon",
  26.     "emu",
  27.     "venus fly-trap",
  28.     "griffin",
  29.     "hobgoblin",
  30.     "ice monster",
  31.     "jabberwock",
  32.     "kestrel",
  33.     "leprechaun",
  34.     "medusa",
  35.     "nymph",
  36.     "orc",
  37.     "phantom",
  38.     "quasit",
  39.     "rattlesnake",
  40.     "snake",
  41.     "troll",
  42.     "black unicorn",
  43.     "vampire",
  44.     "wraith",
  45.     "xeroc",
  46.     "yeti",
  47.     "zombie"
  48. };
  49.  
  50. object mon_tab[MONSTERS] = {
  51.     {(ASLEEP|WAKENS|WANDERS|RUSTS),"0d0",25,'A',20,9,18,100,0,0,0,0,0},
  52.     {(ASLEEP|WANDERS|FLITS),"1d3",10,'B',2,1,8,60,0,0,0,0,0},
  53.     {(ASLEEP|WANDERS),"3d3/2d5",32,'C',15,7,16,85,0,10,0,0,0},
  54.     {(ASLEEP|WAKENS|FLAMES),"4d6/4d9",145,'D',5000,21,126,100,0,90,0,0,0},
  55.     {(ASLEEP|WAKENS),"1d3",11,'E',2,1,7,65,0,0,0,0,0},
  56.     {(HOLDS|STATIONARY),"5d5",73,'F',91,12,126,80,0,0,0,0,0},
  57.     {(ASLEEP|WAKENS|WANDERS|FLIES),"5d5/5d5",115,'G',
  58.             2000,20,126,85,0,10,0,0,0},
  59.     {(ASLEEP|WAKENS|WANDERS),"1d3/1d2",15,'H',3,1,10,67,0,0,0,0,0},
  60.     {(ASLEEP|FREEZES),"0d0",15,'I',5,2,11,68,0,0,0,0,0},
  61.     {(ASLEEP|WANDERS),"3d10/4d5",132,'J',3000,21,126,100,0,0,0,0,0},
  62.     {(ASLEEP|WAKENS|WANDERS|FLIES),"1d4",10,'K',2,1,6,60,0,0,0,0,0},
  63.     {(ASLEEP|STEALS_GOLD),"0d0",25,'L',21,6,16,75,0,0,0,0,0},
  64.     {(ASLEEP|WAKENS|WANDERS|CONFUSES),"4d4/3d7",97,'M',
  65.             250,18,126,85,0,25,0,0,0},
  66.     {(ASLEEP|STEALS_ITEM),"0d0",25,'N',39,10,19,75,0,100,0,0,0},
  67.     {(ASLEEP|WANDERS|WAKENS|SEEKS_GOLD),"1d6",25,'O',5,4,13,70,0,10,0,0,0},
  68.     {(ASLEEP|INVISIBLE|WANDERS|FLITS),"5d4",76,'P',120,15,24,80,0,50,0,0,0},
  69.     {(ASLEEP|WAKENS|WANDERS),"3d5",30,'Q',20,8,17,78,0,20,0,0,0},
  70.     {(ASLEEP|WAKENS|WANDERS|STINGS),"2d5",19,'R',10,3,12,70,0,0,0,0,0},
  71.     {(ASLEEP|WAKENS|WANDERS),"1d3",8,'S',2,1,9,50,0,0,0,0,0},
  72.     {(ASLEEP|WAKENS|WANDERS),"4d6/1d4",75,'T',125,13,22,75,0,33,0,0,0},
  73.     {(ASLEEP|WAKENS|WANDERS),"4d10",90,'U',
  74.             200,17,26,85,0,33,0,0,0},
  75.     {(ASLEEP|WAKENS|WANDERS|DRAINS_LIFE),"1d14/1d4",55,'V',
  76.             350,19,126,85,0,18,0,0,0},
  77.     {(ASLEEP|WANDERS|DROPS_LEVEL),"2d8",45,'W',55,14,23,75,0,0,0,0,0},
  78.     {(ASLEEP|IMITATES),"4d6",42,'X',110,16,25,75,0,0,0,0,0},
  79.     {(ASLEEP|WANDERS),"3d6",35,'Y',50,11,20,80,0,20,0,0,0},
  80.     {(ASLEEP|WAKENS|WANDERS),"1d7",21,'Z',8,5,14,69,0,0,0,0,0}
  81. };
  82.  
  83. extern short cur_level;
  84. extern short cur_room, party_room;
  85. extern short blind, halluc, haste_self;
  86. extern boolean detect_monster, see_invisible, r_see_invisible;
  87. extern short stealthy;
  88.  
  89. put_mons()
  90. {
  91.     short i;
  92.     short n;
  93.     object *monster;
  94.     short row, col;
  95.  
  96.     n = get_rand(4, 6);
  97.  
  98.     for (i = 0; i < n; i++) {
  99.         monster = gr_monster((object *) 0, 0);
  100.         if ((monster->m_flags & WANDERS) && coin_toss()) {
  101.             wake_up(monster);
  102.         }
  103.         gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
  104.         put_m_at(row, col, monster);
  105.     }
  106. }
  107.  
  108. object *
  109. gr_monster(monster, mn)
  110. register object *monster;
  111. register mn;
  112. {
  113.     if (!monster) {
  114.         monster = alloc_object();
  115.  
  116.         for (;;) {
  117.             mn = get_rand(0, MONSTERS-1);
  118.             if ((cur_level >= mon_tab[mn].first_level) &&
  119.             (cur_level <= mon_tab[mn].last_level)) {
  120.                 break;
  121.             }
  122.         }
  123.     }
  124.     *monster = mon_tab[mn];
  125.     if (monster->m_flags & IMITATES) {
  126.         monster->disguise = gr_obj_char();
  127.     }
  128.     if (cur_level > (AMULET_LEVEL + 2)) {
  129.         monster->m_flags |= HASTED;
  130.     }
  131.     monster->trow = NO_ROOM;
  132.     return(monster);
  133. }
  134.  
  135. mv_mons()
  136. {
  137.     register object *monster, *next_monster;
  138.     boolean flew;
  139.  
  140.     if (haste_self % 2) {
  141.         return;
  142.     }
  143.  
  144.     monster = level_monsters.next_monster;
  145.  
  146.     while (monster) {
  147.         next_monster = monster->next_monster;
  148.         if (monster->m_flags & HASTED) {
  149.             mon_disappeared = 0;
  150.             mv_monster(monster, rogue.row, rogue.col);
  151.             if (mon_disappeared) {
  152.                 goto NM;
  153.             }
  154.         } else if (monster->m_flags & SLOWED) {
  155.             monster->slowed_toggle = !monster->slowed_toggle;
  156.             if (monster->slowed_toggle) {
  157.                 goto NM;
  158.             }
  159.         }
  160.         if ((monster->m_flags & CONFUSED) && move_confused(monster)) {
  161.             goto NM;
  162.         }
  163.         flew = 0;
  164.         if ((monster->m_flags & FLIES) && !(monster->m_flags & NAPPING) &&
  165.              !mon_can_go(monster, rogue.row, rogue.col)) {
  166.             flew = 1;
  167.             mv_monster(monster, rogue.row, rogue.col);
  168.         }
  169.         if (!(flew && mon_can_go(monster, rogue.row, rogue.col))) {
  170.             mv_monster(monster, rogue.row, rogue.col);
  171.         }
  172. NM:        monster = next_monster;
  173.     }
  174. }
  175.  
  176. party_monsters(rn, n)
  177. int rn, n;
  178. {
  179.     short i, j;
  180.     short row, col;
  181.     object *monster;
  182.     boolean found;
  183.  
  184.     n += n;
  185.  
  186.     for (i = 0; i < MONSTERS; i++) {
  187.         mon_tab[i].first_level -= (cur_level % 3);
  188.     }
  189.     for (i = 0; i < n; i++) {
  190.         if (no_room_for_monster(rn)) {
  191.             break;
  192.         }
  193.         for (j = found = 0; ((!found) && (j < 250)); j++) {
  194.             row = get_rand(rooms[rn].top_row+1,
  195.                 rooms[rn].bottom_row-1);
  196.             col = get_rand(rooms[rn].left_col+1,
  197.                 rooms[rn].right_col-1);
  198.             if ((!(dungeon[row][col] & MONSTER)) &&
  199.                 (dungeon[row][col] & (FLOOR | TUNNEL))) {
  200.                 found = 1;
  201.             }
  202.         }
  203.         if (found) {
  204.             monster = gr_monster((object *) 0, 0);
  205.             if (!(monster->m_flags & IMITATES)) {
  206.                 monster->m_flags |= WAKENS;
  207.             }
  208.             put_m_at(row, col, monster);
  209.         }
  210.     }
  211.     for (i = 0; i < MONSTERS; i++) {
  212.         mon_tab[i].first_level += (cur_level % 3);
  213.     }
  214. }
  215.  
  216. gmc_row_col(row, col)
  217. register row, col;
  218. {
  219.     register object *monster;
  220.     short retval;
  221.  
  222.     if (monster = object_at(&level_monsters, row, col)) {
  223.         if ((!(detect_monster || see_invisible || r_see_invisible) &&
  224.             (monster->m_flags & INVISIBLE)) || blind) {
  225.             retval = monster->trail_char;
  226.             return(retval);
  227.         }
  228.         if (monster->m_flags & IMITATES) {
  229.             return(monster->disguise);
  230.         }
  231.         return(monster->m_char);
  232.     } else {
  233.         return('&');    /* BUG if this ever happens */
  234.     }
  235. }
  236.  
  237. gmc(monster)
  238. object *monster;
  239. {
  240.     if ((!(detect_monster || see_invisible || r_see_invisible) &&
  241.         (monster->m_flags & INVISIBLE))
  242.         || blind) {
  243.         return(monster->trail_char);
  244.     }
  245.     if (monster->m_flags & IMITATES) {
  246.         return(monster->disguise);
  247.     }
  248.     return(monster->m_char);
  249. }
  250.  
  251. mv_monster(monster, row, col)
  252. register object *monster;
  253. short row, col;
  254. {
  255.     short i, n;
  256.     boolean tried[6];
  257.  
  258.     if (monster->m_flags & ASLEEP) {
  259.         if (monster->m_flags & NAPPING) {
  260.             if (--monster->nap_length <= 0) {
  261.                 monster->m_flags &= (~(NAPPING | ASLEEP));
  262.             }
  263.             return;
  264.         }
  265.         if ((monster->m_flags & WAKENS) &&
  266.              rogue_is_around(monster->row, monster->col) &&
  267.              rand_percent(((stealthy > 0) ?
  268.                  (WAKE_PERCENT / (STEALTH_FACTOR + stealthy)) :
  269.                 WAKE_PERCENT))) {
  270.             wake_up(monster);
  271.         }
  272.         return;
  273.     } else if (monster->m_flags & ALREADY_MOVED) {
  274.         monster->m_flags &= (~ALREADY_MOVED);
  275.         return;
  276.     }
  277.     if ((monster->m_flags & FLITS) && flit(monster)) {
  278.         return;
  279.     }
  280.     if ((monster->m_flags & STATIONARY) &&
  281.         (!mon_can_go(monster, rogue.row, rogue.col))) {
  282.         return;
  283.     }
  284.     if (monster->m_flags & FREEZING_ROGUE) {
  285.         return;
  286.     }
  287.     if ((monster->m_flags & CONFUSES) && m_confuse(monster)) {
  288.         return;
  289.     }
  290.     if (mon_can_go(monster, rogue.row, rogue.col)) {
  291.         mon_hit(monster, (char *) 0, 0);
  292.         return;
  293.     }
  294.     if ((monster->m_flags & FLAMES) && flame_broil(monster)) {
  295.         return;
  296.     }
  297.     if ((monster->m_flags & SEEKS_GOLD) && seek_gold(monster)) {
  298.         return;
  299.     }
  300.     if ((monster->trow == monster->row) &&
  301.            (monster->tcol == monster->col)) {
  302.         monster->trow = NO_ROOM;
  303.     } else if (monster->trow != NO_ROOM) {
  304.         row = monster->trow;
  305.         col = monster->tcol;
  306.     }
  307.     if (monster->row > row) {
  308.         row = monster->row - 1;
  309.     } else if (monster->row < row) {
  310.         row = monster->row + 1;
  311.     }
  312.     if ((dungeon[row][monster->col] & DOOR) &&
  313.          mtry(monster, row, monster->col)) {
  314.         return;
  315.     }
  316.     if (monster->col > col) {
  317.         col = monster->col - 1;
  318.     } else if (monster->col < col) {
  319.         col = monster->col + 1;
  320.     }
  321.     if ((dungeon[monster->row][col] & DOOR) &&
  322.          mtry(monster, monster->row, col)) {
  323.         return;
  324.     }
  325.     if (mtry(monster, row, col)) {
  326.         return;
  327.     }
  328.  
  329.     for (i = 0; i <= 5; i++) tried[i] = 0;
  330.  
  331.     for (i = 0; i < 6; i++) {
  332. NEXT_TRY:    n = get_rand(0, 5);
  333.         switch(n) {
  334.         case 0:
  335.             if (!tried[n] && mtry(monster, row, monster->col-1)) {
  336.                 goto O;
  337.             }
  338.             break;
  339.         case 1:
  340.             if (!tried[n] && mtry(monster, row, monster->col)) {
  341.                 goto O;
  342.             }
  343.             break;
  344.         case 2:
  345.             if (!tried[n] && mtry(monster, row, monster->col+1)) {
  346.                 goto O;
  347.             }
  348.             break;
  349.         case 3:
  350.             if (!tried[n] && mtry(monster, monster->row-1, col)) {
  351.                 goto O;
  352.             }
  353.             break;
  354.         case 4:
  355.             if (!tried[n] && mtry(monster, monster->row, col)) {
  356.                 goto O;
  357.             }
  358.             break;
  359.         case 5:
  360.             if (!tried[n] && mtry(monster, monster->row+1, col)) {
  361.                 goto O;
  362.             }
  363.             break;
  364.         }
  365.         if (!tried[n]) {
  366.             tried[n] = 1;
  367.         } else {
  368.             goto NEXT_TRY;
  369.         }
  370.     }
  371. O:
  372.     if ((monster->row == monster->o_row) && (monster->col == monster->o_col)) {
  373.         if (++(monster->o) > 4) {
  374.             if ((monster->trow == NO_ROOM) &&
  375.                     (!mon_sees(monster, rogue.row, rogue.col))) {
  376.                 monster->trow = get_rand(1, (DROWS - 2));
  377.                 monster->tcol = get_rand(0, (DCOLS - 1));
  378.             } else {
  379.                 monster->trow = NO_ROOM;
  380.                 monster->o = 0;
  381.             }
  382.         }
  383.     } else {
  384.         monster->o_row = monster->row;
  385.         monster->o_col = monster->col;
  386.         monster->o = 0;
  387.     }
  388. }
  389.  
  390. mtry(monster, row, col)
  391. register object *monster;
  392. register short row, col;
  393. {
  394.     if (mon_can_go(monster, row, col)) {
  395.         move_mon_to(monster, row, col);
  396.         return(1);
  397.     }
  398.     return(0);
  399. }
  400.  
  401. move_mon_to(monster, row, col)
  402. register object *monster;
  403. register short row, col;
  404. {
  405.     short c;
  406.     register mrow, mcol;
  407.  
  408.     mrow = monster->row;
  409.     mcol = monster->col;
  410.  
  411.     dungeon[mrow][mcol] &= ~MONSTER;
  412.     dungeon[row][col] |= MONSTER;
  413.  
  414.     c = mvinch(mrow, mcol);
  415.  
  416.     if ((c >= 'A') && (c <= 'Z')) {
  417.         if (!detect_monster) {
  418.             mvaddch(mrow, mcol, monster->trail_char);
  419.         } else {
  420.             if (rogue_can_see(mrow, mcol)) {
  421.                 mvaddch(mrow, mcol, monster->trail_char);
  422.             } else {
  423.                 if (monster->trail_char == '.') {
  424.                     monster->trail_char = ' ';
  425.                 }
  426.                 mvaddch(mrow, mcol, monster->trail_char);
  427.             }
  428.         }
  429.     }
  430.     monster->trail_char = mvinch(row, col);
  431.     if (!blind && (detect_monster || rogue_can_see(row, col))) {
  432.         if ((!(monster->m_flags & INVISIBLE) ||
  433.             (detect_monster || see_invisible || r_see_invisible))) {
  434.             mvaddch(row, col, gmc(monster));
  435.         }
  436.     }
  437.     if ((dungeon[row][col] & DOOR) &&
  438.         (get_room_number(row, col) != cur_room) &&
  439.         (dungeon[mrow][mcol] == FLOOR) && !blind) {
  440.             mvaddch(mrow, mcol, ' ');
  441.     }
  442.     if (dungeon[row][col] & DOOR) {
  443.             dr_course(monster, ((dungeon[mrow][mcol] & TUNNEL) ? 1 : 0),
  444.                 row, col);
  445.     } else {
  446.         monster->row = row;
  447.         monster->col = col;
  448.     }
  449. }
  450.  
  451. mon_can_go(monster, row, col)
  452. register object *monster;
  453. register short row, col;
  454. {
  455.     object *obj;
  456.     short dr, dc;
  457.  
  458.     dr = monster->row - row;    /* check if move distance > 1 */
  459.     if ((dr >= 2) || (dr <= -2)) {
  460.         return(0);
  461.     }
  462.     dc = monster->col - col;
  463.     if ((dc >= 2) || (dc <= -2)) {
  464.         return(0);
  465.     }
  466.     if ((!dungeon[monster->row][col]) || (!dungeon[row][monster->col])) {
  467.         return(0);
  468.     }
  469.     if ((!is_passable(row, col)) || (dungeon[row][col] & MONSTER)) {
  470.         return(0);
  471.     }
  472.     if ((monster->row!=row)&&(monster->col!=col)&&((dungeon[row][col]&DOOR) ||
  473.         (dungeon[monster->row][monster->col]&DOOR))) {
  474.         return(0);
  475.     }
  476.     if (!(monster->m_flags & (FLITS | CONFUSED | CAN_FLIT)) &&
  477.         (monster->trow == NO_ROOM)) {
  478.         if ((monster->row < rogue.row) && (row < monster->row)) return(0);
  479.         if ((monster->row > rogue.row) && (row > monster->row)) return(0);
  480.         if ((monster->col < rogue.col) && (col < monster->col)) return(0);
  481.         if ((monster->col > rogue.col) && (col > monster->col)) return(0);
  482.     }
  483.     if (dungeon[row][col] & OBJECT) {
  484.         obj = object_at(&level_objects, row, col);
  485.         if ((obj->what_is == SCROLL) && (obj->which_kind == SCARE_MONSTER)) {
  486.             return(0);
  487.         }
  488.     }
  489.     return(1);
  490. }
  491.  
  492. wake_up(monster)
  493. object *monster;
  494. {
  495.     if (!(monster->m_flags & NAPPING)) {
  496.         monster->m_flags &= (~(ASLEEP | IMITATES | WAKENS));
  497.     }
  498. }
  499.  
  500. wake_room(rn, entering, row, col)
  501. short rn;
  502. boolean entering;
  503. short row, col;
  504. {
  505.     object *monster;
  506.     short wake_percent;
  507.     boolean in_room;
  508.  
  509.     wake_percent = (rn == party_room) ? PARTY_WAKE_PERCENT : WAKE_PERCENT;
  510.     if (stealthy > 0) {
  511.         wake_percent /= (STEALTH_FACTOR + stealthy);
  512.     }
  513.  
  514.     monster = level_monsters.next_monster;
  515.  
  516.     while (monster) {
  517.         in_room = (rn == get_room_number(monster->row, monster->col));
  518.         if (in_room) {
  519.             if (entering) {
  520.                 monster->trow = NO_ROOM;
  521.             } else {
  522.                 monster->trow = row;
  523.                 monster->tcol = col;
  524.             }
  525.         }
  526.         if ((monster->m_flags & WAKENS) &&
  527.             (rn == get_room_number(monster->row, monster->col))) {
  528.             if (rand_percent(wake_percent)) {
  529.                 wake_up(monster);
  530.             }
  531.         }
  532.         monster = monster->next_monster;
  533.     }
  534. }
  535.  
  536. char *
  537. mon_name(monster)
  538. object *monster;
  539. {
  540.     short ch;
  541.  
  542.     if (blind || ((monster->m_flags & INVISIBLE) &&
  543.         !(detect_monster || see_invisible || r_see_invisible))) {
  544.         return("something");
  545.     }
  546.     if (halluc) {
  547.         ch = get_rand('A', 'Z') - 'A';
  548.         return(m_names[ch]);
  549.     }
  550.     ch = monster->m_char - 'A';
  551.     return(m_names[ch]);
  552. }
  553.  
  554. rogue_is_around(row, col)
  555. register row, col;
  556. {
  557.     short rdif, cdif, retval;
  558.  
  559.     rdif = row - rogue.row;
  560.     cdif = col - rogue.col;
  561.  
  562.     retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
  563.     return(retval);
  564. }
  565.  
  566. wanderer()
  567. {
  568.     object *monster;
  569.     short row, col, i;
  570.     boolean found = 0;
  571.  
  572.     for (i = 0; ((i < 15) && (!found)); i++) {
  573.         monster = gr_monster((object *) 0, 0);
  574.         if (!(monster->m_flags & (WAKENS | WANDERS))) {
  575.             free_object(monster);
  576.         } else {
  577.             found = 1;
  578.         }
  579.     }
  580.     if (found) {
  581.         found = 0;
  582.         wake_up(monster);
  583.         for (i = 0; ((i < 25) && (!found)); i++) {
  584.             gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT));
  585.             if (!rogue_can_see(row, col)) {
  586.                 put_m_at(row, col, monster);
  587.                 found = 1;
  588.             }
  589.         }
  590.         if (!found) {
  591.             free_object(monster);
  592.         }
  593.     }
  594. }
  595.  
  596. show_monsters()
  597. {
  598.     object *monster;
  599.  
  600.     detect_monster = 1;
  601.  
  602.     if (blind) {
  603.         return;
  604.     }
  605.     monster = level_monsters.next_monster;
  606.  
  607.     while (monster) {
  608.         mvaddch(monster->row, monster->col, monster->m_char);
  609.         if (monster->m_flags & IMITATES) {
  610.             monster->m_flags &= (~IMITATES);
  611.             monster->m_flags |= WAKENS;
  612.         }
  613.         monster = monster->next_monster;
  614.     }
  615. }
  616.  
  617. create_monster()
  618. {
  619.     short row, col;
  620.     short i;
  621.     boolean found = 0;
  622.     object *monster;
  623.  
  624.     row = rogue.row;
  625.     col = rogue.col;
  626.  
  627.     for (i = 0; i < 9; i++) {
  628.         rand_around(i, &row, &col);
  629.         if (((row == rogue.row) && (col = rogue.col)) ||
  630.                 (row < MIN_ROW) || (row > (DROWS-2)) ||
  631.                 (col < 0) || (col > (DCOLS-1))) {
  632.             continue;
  633.         }
  634.         if ((!(dungeon[row][col] & MONSTER)) &&
  635.               (dungeon[row][col] & (FLOOR|TUNNEL|STAIRS|DOOR))) {
  636.             found = 1;
  637.             break;
  638.         }
  639.     }
  640.     if (found) {
  641.         monster = gr_monster((object *) 0, 0);
  642.         put_m_at(row, col, monster);
  643.         mvaddch(row, col, gmc(monster));
  644.         if (monster->m_flags & (WANDERS | WAKENS)) {
  645.             wake_up(monster);
  646.         }
  647.     } else {
  648.         message("you hear a faint cry of anguish in the distance", 0);
  649.     }
  650. }
  651.  
  652. put_m_at(row, col, monster)
  653. short row, col;
  654. object *monster;
  655. {
  656.     monster->row = row;
  657.     monster->col = col;
  658.     dungeon[row][col] |= MONSTER;
  659.     monster->trail_char = mvinch(row, col);
  660.     (void) add_to_pack(monster, &level_monsters, 0);
  661.     aim_monster(monster);
  662. }
  663.  
  664. aim_monster(monster)
  665. object *monster;
  666. {
  667.     short i, rn, d, r;
  668.  
  669.     rn = get_room_number(monster->row, monster->col);
  670.     r = get_rand(0, 12);
  671.  
  672.     for (i = 0; i < 4; i++) {
  673.         d = (r + i) % 4;
  674.         if (rooms[rn].doors[d].oth_room != NO_ROOM) {
  675.             monster->trow = rooms[rn].doors[d].door_row;
  676.             monster->tcol = rooms[rn].doors[d].door_col;
  677.             break;
  678.         }
  679.     }
  680. }
  681.  
  682. rogue_can_see(row, col)
  683. register row, col;
  684. {
  685.     register retval;
  686.  
  687.     retval = !blind &&
  688.             (((get_room_number(row, col) == cur_room) &&
  689.                     !(rooms[cur_room].is_room & R_MAZE)) ||
  690.             rogue_is_around(row, col));
  691.  
  692.     return(retval);
  693. }
  694.  
  695. move_confused(monster)
  696. object *monster;
  697. {
  698.     short i, row, col;
  699.  
  700.     if (!(monster->m_flags & ASLEEP)) {
  701.         if (--monster->moves_confused <= 0) {
  702.             monster->m_flags &= (~CONFUSED);
  703.         }
  704.         if (monster->m_flags & STATIONARY) {
  705.             return(coin_toss() ? 1 : 0);
  706.         } else if (rand_percent(15)) {
  707.             return(1);
  708.         }
  709.         row = monster->row;
  710.         col = monster->col;
  711.  
  712.         for (i = 0; i < 9; i++) {
  713.             rand_around(i, &row, &col);
  714.             if ((row == rogue.row) && (col == rogue.col)) {
  715.                 return(0);
  716.             }
  717.             if (mtry(monster, row, col)) {
  718.                 return(1);
  719.             }
  720.         }
  721.     }
  722.     return(0);
  723. }
  724.  
  725. flit(monster)
  726. object *monster;
  727. {
  728.     short i, row, col;
  729.  
  730.     if (!rand_percent(FLIT_PERCENT)) {
  731.         return(0);
  732.     }
  733.     if (rand_percent(10)) {
  734.         return(1);
  735.     }
  736.     row = monster->row;
  737.     col = monster->col;
  738.  
  739.     for (i = 0; i < 9; i++) {
  740.         rand_around(i, &row, &col);
  741.         if ((row == rogue.row) && (col == rogue.col)) {
  742.             continue;
  743.         }
  744.         if (mtry(monster, row, col)) {
  745.             return(1);
  746.         }
  747.     }
  748.     return(1);
  749. }
  750.  
  751. gr_obj_char()
  752. {
  753.     short r;
  754.     char *rs = "%!?]=/):*";
  755.  
  756.     r = get_rand(0, 8);
  757.  
  758.     return(rs[r]);
  759. }
  760.  
  761. no_room_for_monster(rn)
  762. int rn;
  763. {
  764.     short i, j;
  765.  
  766.     for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
  767.         for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
  768.             if (!(dungeon[i][j] & MONSTER)) {
  769.                 return(0);
  770.             }
  771.         }
  772.     }
  773.     return(1);
  774. }
  775.  
  776. aggravate()
  777. {
  778.     object *monster;
  779.  
  780.     message("you hear a high pitched humming noise", 0);
  781.  
  782.     monster = level_monsters.next_monster;
  783.  
  784.     while (monster) {
  785.         wake_up(monster);
  786.         monster->m_flags &= (~IMITATES);
  787.         if (rogue_can_see(monster->row, monster->col)) {
  788.             mvaddch(monster->row, monster->col, monster->m_char);
  789.         }
  790.         monster = monster->next_monster;
  791.     }
  792. }
  793.  
  794. boolean
  795. mon_sees(monster, row, col)
  796. object *monster;
  797. {
  798.     short rn, rdif, cdif, retval;
  799.  
  800.     rn = get_room_number(row, col);
  801.  
  802.     if (    (rn != NO_ROOM) &&
  803.             (rn == get_room_number(monster->row, monster->col)) &&
  804.             !(rooms[rn].is_room & R_MAZE)) {
  805.         return(1);
  806.     }
  807.     rdif = row - monster->row;
  808.     cdif = col - monster->col;
  809.  
  810.     retval = (rdif >= -1) && (rdif <= 1) && (cdif >= -1) && (cdif <= 1);
  811.     return(retval);
  812. }
  813.  
  814. mv_aquatars()
  815. {
  816.     object *monster;
  817.  
  818.     monster = level_monsters.next_monster;
  819.  
  820.     while (monster) {
  821.         if ((monster->m_char == 'A') &&
  822.             mon_can_go(monster, rogue.row, rogue.col)) {
  823.             mv_monster(monster, rogue.row, rogue.col);
  824.             monster->m_flags |= ALREADY_MOVED;
  825.         }
  826.         monster = monster->next_monster;
  827.     }
  828. }
  829.